package kr.zetaomicron.ultrasolitaire;

import android.os.Bundle;
import android.util.Log;
import android.graphics.Canvas;
import java.lang.InterruptedException;
import java.lang.Thread;
import java.util.Stack;

public abstract class Rules {
	public static final int KLONDIKE = 1, SPIDER = 2, FREECELL = 3, FORTYTHIEVES = 4;

	public static final int EVENT_INVALID = -1;
	public static final int EVENT_DEAL = 1;
	public static final int EVENT_STACK_ADD = 2;
	public static final int EVENT_FLING = 3;
	public static final int EVENT_AUTOMOVE = 4;
	public static final int EVENT_SMART_MOVE = 5;
	public static final int EVENT_DEAL_NEXT = 6;

	public static final int AUTO_MOVE_ALWAYS = 2;
	public static final int AUTO_MOVE_FLING_ONLY = 1;
	public static final int AUTO_MOVE_NEVER = 0;

  private int mType;
	protected World mView;
	protected Stack<Move> mMoveHistory, mUndoHistory; 
  protected boolean mIgnoreEvents;
  protected EventPoster mEventPoster;

	// Anchors
	protected CardAnchor[] mCardAnchor;
	protected int mCardAnchorCount;

	protected Deck mDeck;
	protected int mCardCount;

  // Automove
  protected int mAutoMoveLevel;
  protected boolean mWasFling;

  public int GetType() { return mType; }
	public int GetCardCount() {	return mCardCount;	}
	public CardAnchor[] GetAnchorArray() {	return mCardAnchor;	}
  public void SetType(int type) { mType = type; }
  public void SetView(World view) { mView = view; }
	public void SetMoveHistory(Stack<Move> moveHistory) {	mMoveHistory = moveHistory;	}
	public void SetUndoHistory(Stack<Move> undoHistory) {	mUndoHistory = undoHistory;	}
  public void SetIgnoreEvents(boolean ignore) { mIgnoreEvents = ignore; }
  public void SetEventPoster(EventPoster ep) { mEventPoster = ep; }
  public boolean GetIgnoreEvents() { return mIgnoreEvents; }
  public int GetRulesExtra() { return 0; }
  public String GetGameTypeString() { return ""; }
  public String GetPrettyGameTypeString() { return ""; }
  public boolean HasScore() { return false; }
  public boolean HasString() { return false; }
  public String GetString() { return ""; }
  public void SetCarryOverScore(int score) {}
  public int GetScore() { return 0; }
  public void AddDealCount() {}

  public int CountFreeSpaces() { return 0; }
  protected void SignalWin() { /*mView.DisplayWin();*/ }

  abstract public void Init(Bundle map);
  public void EventAlert(int event) { if (!mIgnoreEvents) { mEventPoster.PostEvent(event);/* mView.Refresh();*/ } }
  public void EventAlert(int event, CardAnchor anchor) { if (!mIgnoreEvents) { mEventPoster.PostEvent(event, anchor);/*  mView.Refresh();*/} }
  public void EventAlert(int event, CardAnchor anchor, Card card) { if (!mIgnoreEvents) { mEventPoster.PostEvent(event, anchor, card);/*  mView.Refresh();*/} }
  public void ClearEvent() { mEventPoster.ClearEvent(); }
	abstract public void EventProcess(int event, CardAnchor anchor);
	abstract public void EventProcess(int event, CardAnchor anchor, Card card);
	abstract public void EventProcess(int event);
	abstract public void Resize(int width, int height);
	abstract public void Scroll(boolean tab_found, float deltaY);
	abstract public void ScrollImmed(boolean tab_found, float y);
	public boolean Fling(MoveCard moveCard) {	moveCard.Release();	return false;	}
	public boolean AutoMove(MoveCard moveCard) {	moveCard.Release();	return false;	}
	public void MovePush(int from, int toBegin, int toEnd, int count, boolean invert, boolean unhide) {
		mMoveHistory.push(new Move(from, toBegin, toEnd, count, invert, unhide));
		mUndoHistory.clear();	// Makes redo disabled
	}
	public void MovePush(int from, int to, int count, boolean invert, boolean unhide) {
		mMoveHistory.push(new Move(from, to, count, invert, unhide));
		mUndoHistory.clear();	// Makes redo disabled
	}
	public void MovePush(int from, int to, int count, boolean invert, boolean unhide, boolean addDealCount) {
		mMoveHistory.push(new Move(from, to, count, invert, unhide, addDealCount));
		mUndoHistory.clear();	// Makes redo disabled
	}
	public void MovePush(int from, int toBegin, int toEnd, int count, int flags) {
		mMoveHistory.push(new Move(from, toBegin, toEnd, count, flags));
		mUndoHistory.clear();	// Makes redo disabled
	}
	public void HandleEvents() { 
		while (!mIgnoreEvents && mEventPoster.HasEvent()) {
			//Log.i("[Rules]", "[HandleEvents] handle event");
			mEventPoster.HandleEvent();
		}
	}

  public void RefreshOptions() {
	  mAutoMoveLevel = Rules.AUTO_MOVE_ALWAYS;//mView.GetSettings().getInt("AutoMoveLevel", Rules.AUTO_MOVE_ALWAYS);
	  mWasFling = false;
  }

	public static Rules CreateRules(int type, Bundle map, World view, Stack<Move> moveHistory, Stack<Move> undoHistory) {
		Rules ret = null;
		switch (type) {
		case KLONDIKE:
			ret = new NormalSolitaire();	break;
		case SPIDER:
			//ret = new Spider();	break;
		case FREECELL:
			//ret = new Freecell();	break;
		case FORTYTHIEVES:
			//ret = new FortyThieves();
			break;
		}

	    if (ret != null) {
	    	ret.SetType(type);
	    	ret.SetView(view);
	    	ret.SetMoveHistory(moveHistory);
	    	ret.SetUndoHistory(undoHistory);
	    	ret.SetEventPoster(new EventPoster(ret));
	    	ret.RefreshOptions();
	    	ret.Init(map);
	    }
	    return ret;
	}
}

class NormalSolitaire extends Rules {
	private boolean mDealThree;
	private int mDealsLeft;
	private String mScoreString;
	private int mLastScore;
	private int mCarryOverScore;
	private int SUITS, DECKS, RANKS, DEAL, NUM_FOUNDS, NUM_TABLEAUS, FIRST_TABLEAU;

	@Override
	public void Init(Bundle map) {
		SUITS = 4 + 2 * Settings.gameSettings[0];	DECKS = 1 + Settings.gameSettings[1];
		RANKS = 13 + 5 * Settings.gameSettings[2];	DEAL = 1 + 2 * Settings.gameSettings[3];
		mIgnoreEvents = true;
		Card.SetFaceValue(RANKS);
		//mDealThree = mView.GetSettings().getBoolean("SolitaireDealThree", true);

		// Thirteen total anchors for regular solitaire
		NUM_FOUNDS = SUITS * DECKS;
		NUM_TABLEAUS = 5 + (int)(2 * (float)(SUITS * DECKS) / 4);
		//if (18 == RANKS) {	NUM_TABLEAUS += (int)(NUM_FOUNDS / 4);	}
		//else if (23 == RANKS) {	NUM_TABLEAUS += (int)(NUM_FOUNDS / 2);	}
		if (23 == RANKS) {	++NUM_TABLEAUS;	}
		FIRST_TABLEAU = 2 + NUM_FOUNDS;
		Settings.anchorNum[0] = NUM_TABLEAUS;	// number of tableaus
		Settings.anchorNum[1] = 1 + 2 + NUM_FOUNDS;	// number of stock, waste, and foundations
		Settings.anchor2anchor[0] = Settings.anchor2anchor[1] = Settings.anchor2anchor[2] = 0;
		Settings.anchor2anchor[3] = 1.0f;	Settings.anchor2anchor[4] = 0;	// initializes animation settings
		mCardCount = RANKS * NUM_FOUNDS;
		mCardAnchorCount = 2 + NUM_FOUNDS + NUM_TABLEAUS;
		mCardAnchor = new CardAnchor[mCardAnchorCount];
		// Indices for column scrolls
		//Settings.columnLeftIdxFound = 0;	Settings.columnLeftIdxTab = FIRST_TABLEAU;

		// Top dealt from anchors
		mCardAnchor[0] = CardAnchor.CreateAnchor(CardAnchor.DEAL_FROM, 0, this);	// Stack
		mCardAnchor[1] = CardAnchor.CreateAnchor(CardAnchor.DEAL_TO, 1, this);	// Waste
		if (mDealThree) {
			mCardAnchor[1].SetShowing(3);
		} else {
			mCardAnchor[1].SetShowing(1);
		}

		// Top anchors for placing cards, Foundations, Anchor 2 ~ 5 or 2 ~ 9...
		for (int i = 0; i < SUITS * DECKS; i++) {
			mCardAnchor[i+2] = CardAnchor.CreateAnchor(CardAnchor.SEQ_SINK, i+2, this);
		}

		// Middle anchor stacks, Tableaus, Anchor 6 ~ 12 or 10 ~ 18...
		for (int i = 0; i < NUM_TABLEAUS; i++) {
			mCardAnchor[i + FIRST_TABLEAU] = CardAnchor.CreateAnchor(CardAnchor.GENERIC_ANCHOR, i + FIRST_TABLEAU, this);
			mCardAnchor[i + FIRST_TABLEAU].SetStartSeq(GenericAnchor.START_KING);
			mCardAnchor[i + FIRST_TABLEAU].SetBuildSeq(GenericAnchor.SEQ_DSC);
			mCardAnchor[i + FIRST_TABLEAU].SetMoveSeq(GenericAnchor.SEQ_ASC);
			mCardAnchor[i + FIRST_TABLEAU].SetSuit(GenericAnchor.SUIT_RB);
			mCardAnchor[i + FIRST_TABLEAU].SetWrap(false);
			mCardAnchor[i + FIRST_TABLEAU].SetBehavior(GenericAnchor.PACK_MULTI);
			mCardAnchor[i + FIRST_TABLEAU].SetDisplay(GenericAnchor.DISPLAY_MIX);
		}

		if (map != null) {
			// Do some assertions, default to a new game if we find an invalid state
    		if (map.getInt("cardAnchorCount") == 13 && map.getInt("cardCount") == 52) {
    			int[] cardCount = map.getIntArray("anchorCardCount");
    			int[] hiddenCount = map.getIntArray("anchorHiddenCount");
    			int[] value = map.getIntArray("value");
    			int[] suit = map.getIntArray("suit");
    			int cardIdx = 0;
    			mDealsLeft = map.getInt("rulesExtra");

    			for (int i = 0; i < 13; i++) {
        			for (int j = 0; j < cardCount[i]; j++, cardIdx++) {
        				Card card = new Card(value[cardIdx], suit[cardIdx]);
        				mCardAnchor[i].AddCard(card);
	    			}
	    			mCardAnchor[i].SetHiddenCount(hiddenCount[i]);
	    		}
				if (mDealsLeft != -1) {
					// Reset to zero as GetScore() uses it in its calculation.
					mCarryOverScore = 0;
					mCarryOverScore = map.getInt("score") - GetScore();
				}

				mIgnoreEvents = false;
				// Return here so an invalid save state will result in a new game
				return;
			}
		}

		// if map == null, process the following code.
		mDeck = new Deck(DECKS, SUITS, RANKS);
		for (int i = 0; i < NUM_TABLEAUS; i++) {
			for (int j = 0; j <= i; j++) {
				mCardAnchor[i + FIRST_TABLEAU].AddCard(mDeck.PopCard());
			}
			mCardAnchor[i + FIRST_TABLEAU].SetHiddenCount(i);
		}

		while (!mDeck.Empty()) {
			mCardAnchor[0].AddCard(mDeck.PopCard());
		}

		//if (mView.GetSettings().getBoolean("SolitaireStyleNormal", true)) {
			mDealsLeft = -1;
	//	} else {
//			mDealsLeft = mDealThree ? 2 : 0;
//			mLastScore = -52;
//			mScoreString = "-$52";
//			mCarryOverScore = 0;
//		}
		mIgnoreEvents = false;
	}

	@Override
	public void SetCarryOverScore(int score) {
		mCarryOverScore = score;
	}

	@Override
	public void Resize(int width, int height) {
		// Sets positions and sizes
		int height_avail = height - Settings.BTN_SCROLL_WIDTH * 2;
		float rem = height_avail - Card.HEIGHT * Settings.columnNum;	// between card and card
		int maxWidth = width - (20 + Card.WIDTH);
		rem /= Settings.columnNum;
		for (int i = 0; i < NUM_TABLEAUS; i++) {	// Tableaus
			mCardAnchor[i + FIRST_TABLEAU].SetPosition(width - (20 + 3 * Card.WIDTH / 2), height - Settings.BTN_SCROLL_WIDTH - Card.HEIGHT / 2 - (rem / 2 + i * (rem + Card.HEIGHT)));
			mCardAnchor[i + FIRST_TABLEAU].SetMaxHeight(maxWidth);
		}

		for (int i = NUM_FOUNDS - 1; i >= 0; i--) {	// Foundations
			float coordY = height - Settings.BTN_SCROLL_WIDTH - Card.HEIGHT / 2 - (rem / 2 + (FIRST_TABLEAU - i) * (rem + Card.HEIGHT));
			//mCardAnchor[i + 2].SetPosition(width - (10 + Card.WIDTH / 2), height - Settings.BTN_SCROLL_WIDTH - Card.HEIGHT / 2 - (rem / 2 + (FIRST_TABLEAU - i) * (rem + Card.HEIGHT)));
			mCardAnchor[i + 2].SetPosition(width - (10 + Card.WIDTH / 2), Math.round(coordY));
			//Log.i("[Rules]", "[Resize] coordY == " + String.valueOf(coordY));
		}

		for (int i = 0; i < 2; i++) {	// Anchors 0 and 1, stack & waste
			mCardAnchor[i].SetPosition(width - (10 + Card.WIDTH / 2), height - Settings.BTN_SCROLL_WIDTH - Card.HEIGHT / 2 - (rem / 2 + i * (rem + Card.HEIGHT)));
		}

		float leftAnchorY = Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH
    			- (Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH * 2) / (Settings.columnNum * 2);
    	float anchorHeight = (Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH * 2) / Settings.columnNum;
		ScrollImmed(false, leftAnchorY + anchorHeight * Settings.columnIndices[1]);
		ScrollImmed(true, leftAnchorY + anchorHeight * Settings.columnIndices[0]);

		// Setup edge cards (Touch sensor loses sensitivity towards the edge).
		//mCardAnchor[0].SetLeftEdge(height - Settings.BTN_SCROLL_WIDTH);
		//mCardAnchor[2].SetRightEdge(Settings.BTN_SCROLL_WIDTH);
		//mCardAnchor[FIRST_TABLEAU].SetLeftEdge(height - Settings.BTN_SCROLL_WIDTH);
		//mCardAnchor[FIRST_TABLEAU + NUM_TABLEAUS - 1].SetRightEdge(Settings.BTN_SCROLL_WIDTH);
		for (int i = 0; i < NUM_TABLEAUS; i++) {
			mCardAnchor[i + FIRST_TABLEAU].SetBottom(120);	// status bar
		}
	}
	
	@Override
	public void Scroll(boolean tab_found, float deltaY) {
		if (tab_found) {	// Scrolls tableaus
			//Log.i("[Rules]", "[Scroll] tab y1 == " + String.valueOf(mCardAnchor[FIRST_TABLEAU].GetNewY()) + ", dy == " + String.valueOf(deltaY));
			//Log.i("[Rules]", "[Scroll] tab y1 == " + String.valueOf(mCardAnchor[FIRST_TABLEAU].GetNewY() + deltaY));
			for (int i = 0; i < NUM_TABLEAUS; ++i) {
				mCardAnchor[i + FIRST_TABLEAU].SetPosition(mCardAnchor[i + FIRST_TABLEAU].GetX(), mCardAnchor[i + FIRST_TABLEAU].GetY() + deltaY);
			}
			//Log.i("[Rules]", "[Scroll] tab y2 == " + String.valueOf(mCardAnchor[FIRST_TABLEAU].GetNewY()));
		} else {	// Scrolls foundations
			for (int i = 0; i < FIRST_TABLEAU; ++i) {
				mCardAnchor[i].SetPosition(mCardAnchor[i].GetX(), mCardAnchor[i].GetY() + deltaY);
			}
		}
	}

	@Override
	public void ScrollImmed(boolean tab_found, float y) {	// Scrolls immediately
		float anchorHeight = (Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH * 2) / Settings.columnNum;
		float anchor0Y_original = Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH - anchorHeight / 2;
		// rem == anchorHeight - Card.HEIGHT
		if (tab_found) {	// Scrolls tableaus
			//Log.i("[Rules]", "[ScrollImmed] tab y == " + String.valueOf(y));
			for (int i = 0; i < NUM_TABLEAUS; ++i) {
				mCardAnchor[i + FIRST_TABLEAU].SetPosition(mCardAnchor[i + FIRST_TABLEAU].GetX(), y - i * anchorHeight);
			}
		} else {	// Scrolls foundations
			for (int i = 0; i <= 1; ++i) {	// stock & waste
				mCardAnchor[i].SetPosition(mCardAnchor[i].GetX(), y - i * anchorHeight);
			}
			// Anchor 0's y: Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH - anchorHeight / 2
			for (int i = 2; i < FIRST_TABLEAU; ++i) {	// foundations
				//float coordY = height - Settings.BTN_SCROLL_WIDTH - Card.HEIGHT / 2 - (rem / 2 + (FIRST_TABLEAU - i) * (rem + Card.HEIGHT));
				float coordY = Settings.WORLD_HEIGHT - Settings.BTN_SCROLL_WIDTH - anchorHeight / 2 - (FIRST_TABLEAU - (i - 2)) * anchorHeight;
				mCardAnchor[i].SetPosition(mCardAnchor[i].GetX(), Math.round(coordY + y - anchor0Y_original));
			}
		}
	}

	@Override
	public void EventProcess(int event, CardAnchor anchor) {
		if (mIgnoreEvents) {
			return;
		}
		if (event == EVENT_DEAL) {
			//Log.i("[NormalSolitaire]", "[EventProcess] EVENT_DEAL");
			if (mCardAnchor[0].GetCount() == 0) {
				//Log.i("[Rules]", "[EventProcess] anchor 0 empty");
				boolean addDealCount = false;
				if (mDealsLeft == 0) {
					mCardAnchor[0].SetDone(true);
					return;
				} else if (mDealsLeft > 0) {
					mDealsLeft--;
					addDealCount = true;
				}
				int count = 0;
				while (mCardAnchor[1].GetCount() > 0) {
					mCardAnchor[0].AddCard(mCardAnchor[1].PopCard());
					Settings.setCardAnim(1, 0, 1, true);
					count++;
				}
				MovePush(1, 0, count, true, false, addDealCount);
				//mMoveHistory.push(new Move(1, 0, count, true, false, addDealCount));
			} else {
				int count = 0;
				int maxCount = mDealThree ? 3 : 1;
				for (int i = 0; i < maxCount && mCardAnchor[0].GetCount() > 0; i++) {
					//Log.i("[NormalSolitaire]", "[EventProcess] DealTo added.");
					mCardAnchor[1].AddCard(mCardAnchor[0].PopCard());
					Settings.setCardAnim(0, 1, 1, true);
					count++;
				}
				if (mDealsLeft == 0 && mCardAnchor[0].GetCount() == 0) {
					mCardAnchor[0].SetDone(true);
				}
				MovePush(0, 1, count, true, false);
				//mMoveHistory.push(new Move(0, 1, count, true, false));
			}
		} else if (event == EVENT_AUTOMOVE) {
			//Log.i("[NormalSolitaire]", "[EventProcess] EVENT_AUTOMOVE");
			if (anchor.GetCount() > 0) {
				Card card = anchor.GetCards()[anchor.GetCount() - 1];
				if (!TryToMoveCard(anchor, card)) {
					anchor.AddCard(card);
				}
			}
		} else if (event == EVENT_STACK_ADD) {
			if (mCardAnchor[2].GetCount() == RANKS && mCardAnchor[3].GetCount() == RANKS &&
					mCardAnchor[4].GetCount() == RANKS && mCardAnchor[5].GetCount() == RANKS) {
				//SignalWin();
			}
		}
	}

	@Override
	public void EventProcess(int event, CardAnchor anchor, Card card) {
		if (mIgnoreEvents) {
			anchor.AddCard(card);
			return;
		}
		if (event == EVENT_FLING) {
			mWasFling = true;
			if (!TryToSinkCard(anchor, card)) {
				anchor.AddCard(card);
				mWasFling = false;
			}
		} else if (event == EVENT_AUTOMOVE) {
			if (!TryToMoveCard(anchor, card)) {
				anchor.AddCard(card);
			}
		} else {
			anchor.AddCard(card);
		}
	}

	@Override
	public void EventProcess(int event) {
		if (mIgnoreEvents) {
			return;
		}
		if (event == EVENT_SMART_MOVE) {
			if (mCardAnchor[1].GetCount() > 0 && TryToSink(mCardAnchor[1], 1)) {	// from waste to foundation
				return;
			}
			int i;
			for (i = 0; i < NUM_TABLEAUS; i++) {
				if (mCardAnchor[i+FIRST_TABLEAU].GetCount() > 0 && TryToSink(mCardAnchor[i + FIRST_TABLEAU], i + FIRST_TABLEAU)) {
					break;
				}
			}
			if (i == NUM_TABLEAUS) {
				mWasFling = false;
				Settings.anchor2anchor[4] = 0;	// no more autoplay
			}
		}
	}

	@Override
	public boolean Fling(MoveCard moveCard) {
		if (moveCard.GetCount() == 1) {
			CardAnchor anchor = moveCard.GetAnchor();
			Card card = moveCard.DumpCards(false)[0];
			for (int i = NUM_FOUNDS - 1; i >= 0; --i) {
				//Log.i("[Rules]", "[Fling] i == " + String.valueOf(i));
				if (mCardAnchor[i + 2].DropSingleCard(card)) {
					EventAlert(EVENT_FLING, anchor, card);
					return true;
				}
			}
			anchor.AddCard(card);
		} else {
			moveCard.Release();
		}
		return false;
	}
	
	@Override
	public boolean AutoMove(MoveCard moveCard) {
		Log.i("[Rules]", "[AutoMove] count == " + String.valueOf(moveCard.GetCount()));
		if (moveCard.GetCount() == 1) {
			CardAnchor anchor = moveCard.GetAnchor();
			Card card = moveCard.DumpCards(false)[0];
			for (int i = NUM_FOUNDS - 1; i >= 0; --i) {
				//Log.i("[Rules]", "[Fling] i == " + String.valueOf(i));
				if (mCardAnchor[i + 2].DropSingleCard(card)) {
					EventAlert(EVENT_FLING, anchor, card);
					return true;
				}
			}
			for (int i = 0; i < NUM_TABLEAUS; ++i) {
				Log.i("[Rules]", "[AutoMove] i == " + String.valueOf(i));
				if (mCardAnchor[FIRST_TABLEAU + i].DropSingleCard(card)) {
					EventAlert(EVENT_AUTOMOVE, anchor, card);
					return true;
				}
			}
			anchor.AddCard(card);
		} else {
			moveCard.Release();
		}
		return false;
	}

	private boolean TryToSink(CardAnchor anchor, int idx) {
		Card card = anchor.PopCard();
	    boolean ret = TryToSinkCard(anchor, idx, card);
	    if (!ret) {
	    	anchor.AddCard(card);
	    }
	    return ret;
	}
	
	private boolean TryToSinkCard(CardAnchor anchor, Card card) {
		for (int i = NUM_FOUNDS - 1; i >= 0; --i) {
			if (mCardAnchor[i + 2].DropSingleCard(card)) {
				MovePush(anchor.GetNumber(), i + 2, 1, false, anchor.UnhideTopCard());
				//mMoveHistory.push(new Move(anchor.GetNumber(), i + 2, 1, false, anchor.UnhideTopCard()));
				Settings.setCardAnim(-1, i + 2, 1, true);
				mCardAnchor[i + 2].AddCard(card);
				return true;
			}
		}

		return false;
	}
	
	private boolean TryToMoveCard(CardAnchor anchor, Card card) {
		Log.i("[Rules]", "[TryToMoveCard]");
		for (int i = 0; i < NUM_TABLEAUS; ++i) {
			if (mCardAnchor[FIRST_TABLEAU + i].DropSingleCard(card)) {
				MovePush(anchor.GetNumber(), FIRST_TABLEAU + i, 1, false, anchor.UnhideTopCard());
				//mMoveHistory.push(new Move(anchor.GetNumber(), FIRST_TABLEAU + i, 1, false, anchor.UnhideTopCard()));
				Settings.setCardAnim(-1, i + 2, 1, true);
				mCardAnchor[FIRST_TABLEAU + i].AddCard(card);
				return true;
			}
		}

		return false;
	}

	private boolean TryToSinkCard(CardAnchor anchor, int idx, Card card) {
		for (int i = NUM_FOUNDS - 1; i >= 0; --i) {
			if (mCardAnchor[i + 2].DropSingleCard(card)) {
				MovePush(anchor.GetNumber(), i + 2, 1, false, anchor.UnhideTopCard());
				//mMoveHistory.push(new Move(anchor.GetNumber(), i + 2, 1, false, anchor.UnhideTopCard()));
				Settings.setCardAnim(idx, i + 2, 1, true);
				mCardAnchor[i + 2].AddCard(card);
				return true;
			}
		}

		return false;
	}

  @Override
  public int GetRulesExtra() {
    return mDealsLeft;
  }

	@Override
	public String GetGameTypeString() {
		if (mDealsLeft == -1) {
			if (mDealThree) {
				return "KlondikeNormalDeal3";
			} else {
				return "KlondikeNormalDeal1";
			}
		} else {
			if (mDealThree) {
				return "SolitaireVegasDeal3";
			} else {
				return "SolitaireVegasDeal1";
			}
		}
	}

	@Override
	public String GetPrettyGameTypeString() {
		if (mDealsLeft == -1) {
			if (mDealThree) {
				return "Solitaire Dealing Three Cards";
			} else {
				return "Solitaire Dealing One Card";
			}
		} else {
			if (mDealThree) {
				return "Vegas Solitaire Dealing Three Cards";
			} else {
				return "Vegas Solitaire Dealing One Card";
			}
		}
	}

	@Override
	public boolean HasScore() {
		if (mDealsLeft != -1) {
			return true;
		}
		return false;
	}

	@Override
	public boolean HasString() {
		return HasScore();
	}

	@Override
	public String GetString() {
		if (mDealsLeft != -1) {
			int score = mCarryOverScore - 52;
			for (int i = 0; i < 4; i++) {
				score += 5 * mCardAnchor[i+2].GetCount();
			}
			if (score != mLastScore) {
				if (score < 0) {
					mScoreString = "-$" + (score * -1);
				} else {
					mScoreString = "$" + score;
				}
			}
			return mScoreString;
		}
		return "";
	}

	@Override
	public int GetScore() {
		if (mDealsLeft != -1) {
			int score = mCarryOverScore - 52;
			for (int i = 0; i < 4; i++) {
				score += 5 * mCardAnchor[i+2].GetCount();
			}
			return score;
		}
		return 0;
	}

	@Override
	public void AddDealCount() {
		if (mDealsLeft != -1) {
			mDealsLeft++;
			mCardAnchor[0].SetDone(false);
		}
	}
}

//class Spider extends Rules {
//  private boolean mStillDealing;
//  public void Init(Bundle map) {
//    mIgnoreEvents = true;
//    mStillDealing = false;
//
//    mCardCount = 104;
//    mCardAnchorCount = 12;
//    //mCardAnchor = new CardAnchor[mCardAnchorCount];
//
//    // Anchor stacks
//    for (int i = 0; i < 10; i++) {
////      mCardAnchor[i] = CardAnchor.CreateAnchor(CardAnchor.SPIDER_STACK, i, this);
////      mCardAnchor[i] = CardAnchor.CreateAnchor(CardAnchor.GENERIC_ANCHOR, i, this);
////      mCardAnchor[i].SetBuildSeq(GenericAnchor.SEQ_DSC);
////      mCardAnchor[i].SetBuildSuit(GenericAnchor.SEQ_ANY);
////      mCardAnchor[i].SetMoveSeq(GenericAnchor.SEQ_ASC);
////      mCardAnchor[i].SetMoveSuit(GenericAnchor.SUIT_SAME);
////      mCardAnchor[i].SetBehavior(GenericAnchor.PACK_MULTI);
////      mCardAnchor[i].SetDisplay(GenericAnchor.DISPLAY_MIX);
////      mCardAnchor[i].SetHack(GenericAnchor.DEALHACK);
//    }
//
//    //mCardAnchor[10] = CardAnchor.CreateAnchor(CardAnchor.DEAL_FROM, 10, this);
//    //mCardAnchor[11] = CardAnchor.CreateAnchor(CardAnchor.DEAL_TO, 11, this);
//
//    if (map != null) {
//      // Do some assertions, default to a new game if we find an invalid state
//      if (map.getInt("cardAnchorCount") == 12 &&
//          map.getInt("cardCount") == 104) {
//        int[] cardCount = map.getIntArray("anchorCardCount");
//        int[] hiddenCount = map.getIntArray("anchorHiddenCount");
//        int[] value = map.getIntArray("value");
//        int[] suit = map.getIntArray("suit");
//        int cardIdx = 0;
//
//        for (int i = 0; i < mCardAnchorCount; i++) {
//          for (int j = 0; j < cardCount[i]; j++, cardIdx++) {
//            Card card = new Card(value[cardIdx], suit[cardIdx]);
//            mCardAnchor[i].AddCard(card);
//          }
//          mCardAnchor[i].SetHiddenCount(hiddenCount[i]);
//        }
//
//        mIgnoreEvents = false;
//        // Return here so an invalid save state will result in a new game
//        return;
//      }
//    }
//
//    int suits = mView.GetSettings().getInt("SpiderSuits", 4);
//    mDeck = new Deck(2, suits);
//    int i = 54;
//    while (i > 0) {
//      for (int j = 0; j < 10 && i > 0; j++) {
//        i--;
//        mCardAnchor[j].AddCard(mDeck.PopCard());
//        mCardAnchor[j].SetHiddenCount(mCardAnchor[j].GetCount() - 1);
//      }
//    }
//
//    while (!mDeck.Empty()) {
//      mCardAnchor[10].AddCard(mDeck.PopCard());
//    }
//    mIgnoreEvents = false;
//  }
//
//  public void Resize(int width, int height) {
//    int rem = (width - (Card.WIDTH * 10)) / 10;
//    for (int i = 0; i < 10; i++) {
//      mCardAnchor[i].SetPosition(rem/2 + i * (rem + Card.WIDTH), 10);
//      mCardAnchor[i].SetMaxHeight(height-10);
//    }
//    // Setup edge cards (Touch sensor loses sensitivity towards the edge).
//    mCardAnchor[0].SetLeftEdge(0);
//    mCardAnchor[9].SetRightEdge(width);
//
//    for (int i = 0; i < 10; i++) {
//      mCardAnchor[i].SetBottom(height);
//    }
//    // These two are offscreen as the user doesn't need to see them, but they
//    // are needed to hold onto out of play cards.
//    mCardAnchor[10].SetPosition(-50, 1);
//    mCardAnchor[11].SetPosition(-50, 1);
//  }
//
//  @Override
//  public void EventProcess(int event) {
//  }
//
//  @Override
//  public void EventProcess(int event, CardAnchor anchor, Card card) {
//    anchor.AddCard(card);
//  }
//
//  @Override
//  public void EventProcess(int event, CardAnchor anchor) {
//    if (mIgnoreEvents) {
//      return;
//    }
//    if (event == EVENT_STACK_ADD) {
//      if (anchor.GetCount() - anchor.GetHiddenCount() >= 13) {
//        Card[] card = anchor.GetCards();
//        if (card[anchor.GetCount()-1].GetValue() == 1) {
//          int suit = card[anchor.GetCount()-1].GetSuit();
//          int val = 2;
//          for (int i = anchor.GetCount() - 2; i >= 0 && val < 14; i--, val++) {
//            if (card[i].GetValue() != val || card[i].GetSuit() != suit) {
//              break;
//            }
//          }
//          if (val == 14) {
//            for (int j = 0; j < 13; j++) {
//              mCardAnchor[11].AddCard(anchor.PopCard());
//            }
//            mMoveHistory.push(new Move(anchor.GetNumber(), 11, 13, true, anchor.UnhideTopCard()));
//
//            if (mCardAnchor[11].GetCount() == mCardCount) {
//              SignalWin();
//            }
//          }
//        }
//      }
//      if (mStillDealing) {
//        // Post another event if we aren't done yet.
//        EventAlert(EVENT_DEAL_NEXT, mCardAnchor[anchor.GetNumber()+1]);
//      }
//    } else if (event == EVENT_DEAL) {
//      if (mCardAnchor[10].GetCount() > 0) {
//        int count = mCardAnchor[10].GetCount() > 10 ? 10 : mCardAnchor[10].GetCount();
//        mAnimateCard.MoveCard(mCardAnchor[10].PopCard(), mCardAnchor[0]);
//        mMoveHistory.push(new Move(10, 0, count-1, 1, false, false));
//        mStillDealing = true;
//      }
//    } else if (event == EVENT_DEAL_NEXT) {
//      if (mCardAnchor[10].GetCount() > 0 && anchor.GetNumber() < 10) {
//        mAnimateCard.MoveCard(mCardAnchor[10].PopCard(), anchor);
//      } else {
//        mView.StopAnimating();
//        mStillDealing = false;
//      }
//    }
//  }
//
//  @Override
//  public String GetGameTypeString() {
//    int suits = mView.GetSettings().getInt("SpiderSuits", 4);
//    if (suits == 1) {
//      return "Spider1Suit";
//    } else if (suits == 2) {
//      return "Spider2Suit";
//    } else {
//      return "Spider4Suit";
//    }
//  }
//  @Override
//  public String GetPrettyGameTypeString() {
//    int suits = mView.GetSettings().getInt("SpiderSuits", 4);
//    if (suits == 1) {
//      return "Spider One Suit";
//    } else if (suits == 2) {
//      return "Spider Two Suit";
//    } else {
//      return "Spider Four Suit";
//    }
//  }
//
//  @Override
//  public boolean HasString() {
//    return true;
//  }
//
//  @Override
//  public String GetString() {
//    int dealCount = mCardAnchor[10].GetCount() / 10;
//    if (dealCount == 1) {
//      return "1 deal left";
//    }
//    return dealCount + " deals left";
//  }
//
//}

//class Freecell extends Rules {
//
//  public void Init(Bundle map) {
//    mIgnoreEvents = true;
//
//    // Thirteen total anchors for regular solitaire
//    mCardCount = 52;
//    mCardAnchorCount = 16;
//    mCardAnchor = new CardAnchor[mCardAnchorCount];
//
//    // Top anchors for holding cards
//    for (int i = 0; i < 4; i++) {
//      mCardAnchor[i] = CardAnchor.CreateAnchor(CardAnchor.FREECELL_HOLD, i, this);
//    }
//
//    // Top anchors for sinking cards
//    for (int i = 0; i < 4; i++) {
//      mCardAnchor[i+4] = CardAnchor.CreateAnchor(CardAnchor.SEQ_SINK, i+4, this);
//    }
//
//    // Middle anchor stacks
//    for (int i = 0; i < 8; i++) {
//      mCardAnchor[i+8] = CardAnchor.CreateAnchor(CardAnchor.FREECELL_STACK, i+8,
//                                                 this);
//    }
//
//    if (map != null) {
//      // Do some assertions, default to a new game if we find an invalid state
//      if (map.getInt("cardAnchorCount") == 16 &&
//          map.getInt("cardCount") == 52) {
//        int[] cardCount = map.getIntArray("anchorCardCount");
//        int[] hiddenCount = map.getIntArray("anchorHiddenCount");
//        int[] value = map.getIntArray("value");
//        int[] suit = map.getIntArray("suit");
//        int cardIdx = 0;
//
//        for (int i = 0; i < 16; i++) {
//          for (int j = 0; j < cardCount[i]; j++, cardIdx++) {
//            Card card = new Card(value[cardIdx], suit[cardIdx]);
//            mCardAnchor[i].AddCard(card);
//          }
//          mCardAnchor[i].SetHiddenCount(hiddenCount[i]);
//        }
//
//        mIgnoreEvents = false;
//        // Return here so an invalid save state will result in a new game
//        return;
//      }
//    }
//
//    mDeck = new Deck(1);
//    while (!mDeck.Empty()) {
//      for (int i = 0; i < 8 && !mDeck.Empty(); i++) {
//        mCardAnchor[i+8].AddCard(mDeck.PopCard());
//      }
//    }
//    mIgnoreEvents = false;
//  }
//
//  public void Resize(int width, int height) {
//    int rem = (width - (Card.WIDTH * 8)) / 8;
//    for (int i = 0; i < 8; i++) {
//      mCardAnchor[i].SetPosition(rem/2 + i * (rem + Card.WIDTH), 10);
//      mCardAnchor[i+8].SetPosition(rem/2 + i * (rem + Card.WIDTH), 30 + Card.HEIGHT);
//      mCardAnchor[i+8].SetMaxHeight(height - 30 - Card.HEIGHT);
//    }
//
//    // Setup edge cards (Touch sensor loses sensitivity towards the edge).
//    mCardAnchor[0].SetLeftEdge(0);
//    mCardAnchor[7].SetRightEdge(width);
//    mCardAnchor[8].SetLeftEdge(0);
//    mCardAnchor[15].SetRightEdge(width);
//    for (int i = 0; i < 8; i++) {
//      mCardAnchor[i+8].SetBottom(height);
//    }
//  }
//
//  public void EventProcess(int event, CardAnchor anchor) {
//    if (mIgnoreEvents) {
//      return;
//    }
//    if (event == EVENT_STACK_ADD) {
//      if (anchor.GetNumber() >= 4 && anchor.GetNumber() < 8) {
//        if (mCardAnchor[4].GetCount() == 13 && mCardAnchor[5].GetCount() == 13 &&
//            mCardAnchor[6].GetCount() == 13 && mCardAnchor[7].GetCount() == 13) {
//          SignalWin();
//        } else {
//          if (mAutoMoveLevel == AUTO_MOVE_ALWAYS ||
//              (mAutoMoveLevel == AUTO_MOVE_FLING_ONLY && mWasFling)) {
//            EventAlert(EVENT_SMART_MOVE);
//          } else {
//            mView.StopAnimating();
//            mWasFling = false;
//          }
//        }
//      }
//    }
//  }
//
//  @Override
//  public boolean Fling(MoveCard moveCard) {
//    if (moveCard.GetCount() == 1) {
//      CardAnchor anchor = moveCard.GetAnchor();
//      Card card = moveCard.DumpCards(false)[0];
//      for (int i = 0; i < 4; i++) {
//        if (mCardAnchor[i+4].DropSingleCard(card)) {
//          EventAlert(EVENT_FLING, anchor, card);
//          return true;
//        }
//      }
//      anchor.AddCard(card);
//    } else {
//      moveCard.Release();
//    }
//
//    return false;
//  }
//
//  @Override
//  public void EventProcess(int event, CardAnchor anchor, Card card) {
//    if (mIgnoreEvents) {
//      anchor.AddCard(card);
//      return;
//    }
//    if (event == EVENT_FLING) {
//      mWasFling = true;
//      if (!TryToSinkCard(anchor, card)) {
//        anchor.AddCard(card);
//        mWasFling = false;
//      }
//    } else {
//      anchor.AddCard(card);
//    }
//  }
//
//  private boolean TryToSink(CardAnchor anchor) {
//    Card card = anchor.PopCard();
//    boolean ret = TryToSinkCard(anchor, card);
//    if (!ret) {
//      anchor.AddCard(card);
//    }
//    return ret;
//  }
//
//  private boolean TryToSinkCard(CardAnchor anchor, Card card) {
//    for (int i = 0; i < 4; i++) {
//      if (mCardAnchor[i+4].DropSingleCard(card)) {
//        mAnimateCard.MoveCard(card, mCardAnchor[i+4]);
//        mMoveHistory.push(new Move(anchor.GetNumber(), i+4, 1, false, false));
//        return true;
//      }
//    }
//
//    return false;
//  }
//
//  @Override
//  public void EventProcess(int event) {
//    if (mIgnoreEvents == true) {
//      return;
//    }
//    if (event == EVENT_SMART_MOVE) {
//      for (int i = 0; i < 4; i++) {
//        if (mCardAnchor[i].GetCount() > 0 &&
//            TryToSink(mCardAnchor[i])) {
//          return;
//        }
//      }
//      for (int i = 0; i < 8; i++) {
//        if (mCardAnchor[i+8].GetCount() > 0 &&
//            TryToSink(mCardAnchor[i+8])) {
//          return;
//        }
//      }
//      mWasFling = false;
//      mView.StopAnimating();
//    }
//  }
//
//  @Override
//  public int CountFreeSpaces() {
//    int free = 0;
//    for (int i = 0; i < 4; i++) {
//      if (mCardAnchor[i].GetCount() == 0) {
//        free++;
//      }
//    }
//    for (int i = 0; i < 8; i++) {
//      if (mCardAnchor[i+8].GetCount() == 0) {
//        free++;
//      }
//    }
//    return free;
//  }
//
//  @Override
//  public String GetGameTypeString() {
//    return "Freecell";
//  }
//  @Override
//  public String GetPrettyGameTypeString() {
//    return "Freecell";
//  }
//}

//class FortyThieves extends Rules {
//
//  public void Init(Bundle map) {
//    mIgnoreEvents = true;
//
//    mCardCount = 104;
//    mCardAnchorCount = 20;
//    mCardAnchor = new CardAnchor[mCardAnchorCount];
//
//    // Anchor stacks
//    for (int i = 0; i < 10; i++) {
//      mCardAnchor[i] = CardAnchor.CreateAnchor(CardAnchor.GENERIC_ANCHOR, i, this);
//      mCardAnchor[i].SetBuildSeq(GenericAnchor.SEQ_DSC);
//      mCardAnchor[i].SetMoveSeq(GenericAnchor.SEQ_ASC);
//      mCardAnchor[i].SetSuit(GenericAnchor.SUIT_SAME);
//      mCardAnchor[i].SetWrap(false);
//      mCardAnchor[i].SetPickup(GenericAnchor.PACK_LIMIT_BY_FREE);
//      mCardAnchor[i].SetDropoff(GenericAnchor.PACK_MULTI);
//      mCardAnchor[i].SetDisplay(GenericAnchor.DISPLAY_ALL);
//    }
//    // Bottom anchors for holding cards
//    for (int i = 0; i < 8; i++) {
//      mCardAnchor[i+10] = CardAnchor.CreateAnchor(CardAnchor.SEQ_SINK, i+10, this);
//    }
//    
//    mCardAnchor[18] = CardAnchor.CreateAnchor(CardAnchor.DEAL_FROM, 18, this);
//    mCardAnchor[19] = CardAnchor.CreateAnchor(CardAnchor.DEAL_TO, 19, this);
//
//    if (map != null) {
//      // Do some assertions, default to a new game if we find an invalid state
//      if (map.getInt("cardAnchorCount") == 20 &&
//          map.getInt("cardCount") == 104) {
//        int[] cardCount = map.getIntArray("anchorCardCount");
//        int[] hiddenCount = map.getIntArray("anchorHiddenCount");
//        int[] value = map.getIntArray("value");
//        int[] suit = map.getIntArray("suit");
//        int cardIdx = 0;
//
//        for (int i = 0; i < 20; i++) {
//          for (int j = 0; j < cardCount[i]; j++, cardIdx++) {
//            Card card = new Card(value[cardIdx], suit[cardIdx]);
//            mCardAnchor[i].AddCard(card);
//          }
//          mCardAnchor[i].SetHiddenCount(hiddenCount[i]);
//        }
//
//        mIgnoreEvents = false;
//        // Return here so an invalid save state will result in a new game
//        return;
//      }
//    }
//
//    mDeck = new Deck(2);
//    for (int i = 0; i < 10; i++) {
//      for (int j = 0; j < 4; j++){
//        mCardAnchor[i].AddCard(mDeck.PopCard());
//      }
//    }
//    while (!mDeck.Empty()) {
//      mCardAnchor[18].AddCard(mDeck.PopCard());
//    }
//    mIgnoreEvents = false;
//  }
//
//  public void Resize(int width, int height) {
//    int rem = (width - (Card.WIDTH * 10)) / 10;
//    for (int i = 0; i < 10; i++) {
//      mCardAnchor[i].SetMaxHeight(height - 30 - Card.HEIGHT);
//      mCardAnchor[i].SetPosition(rem/2 + i * (rem + Card.WIDTH), 30 + Card.HEIGHT);
//      
//      mCardAnchor[i+10].SetPosition(rem/2 + i * (rem + Card.WIDTH), 10);
//    }
//
//    // Setup edge cards (Touch sensor loses sensitivity towards the edge).
//    mCardAnchor[0].SetLeftEdge(0);
//    mCardAnchor[9].SetRightEdge(width);
//    mCardAnchor[10].SetLeftEdge(0);
//    mCardAnchor[19].SetRightEdge(width);
//    for (int i = 0; i < 10; i++) {
//      mCardAnchor[i].SetBottom(height);
//    }
//  }
//
//  @Override
//  public boolean Fling(MoveCard moveCard) {
//    if (moveCard.GetCount() == 1) {
//      CardAnchor anchor = moveCard.GetAnchor();
//      Card card = moveCard.DumpCards(false)[0];
//      for (int i = 0; i < 8; i++) {
//        if (mCardAnchor[i+10].DropSingleCard(card)) {
//          mEventPoster.PostEvent(EVENT_FLING, anchor, card);
//          return true;
//        }
//      }
//      anchor.AddCard(card);
//    } else {
//      moveCard.Release();
//    }
//    return false;
//  }
//
//  @Override
//  public void EventProcess(int event, CardAnchor anchor, Card card) {
//    if (mIgnoreEvents) {
//      anchor.AddCard(card);
//      return;
//    }
//    if (event == EVENT_FLING) {
//      mWasFling = true;
//      if (!TryToSinkCard(anchor, card)) {
//        anchor.AddCard(card);
//        mWasFling = false;
//      }
//    } else {
//      anchor.AddCard(card);
//    }
//  }
//  
//  private boolean TryToSink(CardAnchor anchor) {
//    Card card = anchor.PopCard();
//    boolean ret = TryToSinkCard(anchor, card);
//    if (!ret) {
//      anchor.AddCard(card);
//    }
//    return ret;
//  }
//
//  private boolean TryToSinkCard(CardAnchor anchor, Card card) {
//    for (int i = 0; i < 8; i++) {
//      if (mCardAnchor[i+10].DropSingleCard(card)) {
//        mAnimateCard.MoveCard(card, mCardAnchor[i+10]);
//        mMoveHistory.push(new Move(anchor.GetNumber(), i+10, 1, false, false));
//        return true;
//      }
//    }
//    return false;
//  }
//
//  @Override
//  public void EventProcess(int event, CardAnchor anchor) {
//    if (mIgnoreEvents) {
//      return;
//    }
//    if (event == EVENT_DEAL) {
//      if (mCardAnchor[18].GetCount()>0){
//        mCardAnchor[19].AddCard(mCardAnchor[18].PopCard());
//        if (mCardAnchor[18].GetCount() == 0) {
//          mCardAnchor[18].SetDone(true);
//        }
//        mMoveHistory.push(new Move(18, 19, 1, true, false));
//      }
//    } else if (event == EVENT_STACK_ADD) {
//      if (anchor.GetNumber() >= 10 && anchor.GetNumber() < 18) {
//        if (mCardAnchor[10].GetCount() == 13 && mCardAnchor[11].GetCount() == 13 &&
//            mCardAnchor[12].GetCount() == 13 && mCardAnchor[13].GetCount() == 13 &&
//            mCardAnchor[14].GetCount() == 13 && mCardAnchor[15].GetCount() == 13 &&
//            mCardAnchor[16].GetCount() == 13 && mCardAnchor[17].GetCount() == 13) {
//          SignalWin();
//        } else {
//          if (mAutoMoveLevel == AUTO_MOVE_ALWAYS ||
//              (mAutoMoveLevel == AUTO_MOVE_FLING_ONLY && mWasFling)) {
//            mEventPoster.PostEvent(EVENT_SMART_MOVE);
//          } else {
//            mView.StopAnimating();
//            mWasFling = false;
//          }
//        }
//      }
//    }
//  }
//  
//  @Override
//  public void EventProcess(int event) {
//    if (mIgnoreEvents == true) {
//      return;
//    }
//    if (event == EVENT_SMART_MOVE) {
//      for (int i = 0; i < 10; i++) {
//        if (mCardAnchor[i].GetCount() > 0 &&
//            TryToSink(mCardAnchor[i])) {
//          return;
//        }
//      }
//      mWasFling = false;
//      mView.StopAnimating();
//    }
//  }
//
//  @Override
//  public int CountFreeSpaces() {
//    int free = 0;
//    for (int i = 0; i < 10; i++) {
//      if (mCardAnchor[i].GetCount() == 0) {
//        free++;
//      }
//    }
//    return free;
//  }
//
//  @Override
//  public String GetGameTypeString() {
//    return "Forty Thieves";
//  }
//  @Override
//  public String GetPrettyGameTypeString() {
//    return "Forty Thieves";
//  }
//  
//  @Override
//  public boolean HasString() {
//    return true;
//  }
//
//  @Override
//  public String GetString() {
//    int cardsLeft = mCardAnchor[18].GetCount();
//    if (cardsLeft == 1) {
//      return "1 card left";
//    }
//    return cardsLeft + " cards left";
//  }
//  
//}

class EventPoster {
	private int mEvent;
	private CardAnchor mCardAnchor;
	private Card mCard;
	private Rules mRules;

	public EventPoster(Rules rules) {
		mRules = rules;
		mEvent = -1;
		mCardAnchor = null;
		mCard = null;
	}

	public void PostEvent(int event) {
		PostEvent(event, null, null);
	}

	public void PostEvent(int event, CardAnchor anchor) {
		//Log.i("[EventPoster]", "[PostEvent] event posted.");
		PostEvent(event, anchor, null);
	}

	public void PostEvent(int event, CardAnchor anchor, Card card) {
		mEvent = event;
		mCardAnchor = anchor;
		mCard = card;
	}

	public void ClearEvent() {
		mEvent = Rules.EVENT_INVALID;
		mCardAnchor = null;
		mCard = null;
	}

	public boolean HasEvent() {
		return mEvent != Rules.EVENT_INVALID;
	}

	public void HandleEvent() {
		if (HasEvent()) {
			int event = mEvent;
			//Log.i("[EventPoster]", "[HandleEvent] event taken: " + String.valueOf(event));
			CardAnchor cardAnchor = mCardAnchor;
			Card card = mCard;
			ClearEvent();
			if (cardAnchor != null && card != null) {
				mRules.EventProcess(event, cardAnchor, card);
			} else if (cardAnchor != null) {
				mRules.EventProcess(event, cardAnchor);
			} else {
				mRules.EventProcess(event);
			}
		}
	}
}